#include "header.h"

void Multicast(void)
{
	int sockfd, ret;
	unsigned int socklen;
	char buf[MAX_MULTICAST_PKT_LEN], ip[MAX_IPV4_IP_LEN], clientIP[MAX_IPV4_IP_LEN];
	char *retIP;
	struct sockaddr_in saddr;
	struct ip_mreq imreq;

	memset(&saddr, 0, sizeof(struct sockaddr_in));
	memset(&imreq, 0, sizeof(struct ip_mreq));

	sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
	if (FAILURE == sockfd) {
		printf("Error while creating socket\n");
		goto end;
	}

	saddr.sin_family = PF_INET;
	saddr.sin_port = htons(MULTICAST_PORT);
	saddr.sin_addr.s_addr = htonl(INADDR_ANY);

	ret = bind(sockfd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
	if (FAILURE == ret) {
		perror("Error while binding the socket\n");
		goto end;
	}

	imreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_IP);
	imreq.imr_interface.s_addr = INADDR_ANY;

	// JOIN multicast group on default interface
	ret = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&imreq, sizeof(struct ip_mreq));

	socklen = sizeof(struct sockaddr_in);

	while (1) {
		recvfrom(sockfd, buf, MAX_MULTICAST_PKT_LEN, 0, (struct sockaddr *)&saddr, &socklen);

		//Send the IP address to corrosponding host
		if (SUCCESS == strncmp(buf, MULTICAST_REQ_MSG, strlen(MULTICAST_REQ_MSG))) {

			inet_ntop(AF_INET, &saddr.sin_addr.s_addr, clientIP, MAX_IPV4_IP_LEN);
			printf("IP requested by client :%s\n", clientIP);

			retIP = getSystemIP(ip, INTERFACE);
			if (NULL == retIP) {
				printf("Unable to get system IP\n");
			}

			strcpy(buf, MULTICAST_RES_MSG);
			strcat(buf, ip);
			strcat(buf, "#");

			sleep(1);//Make sure that the client is in recv state
			ret = sendto(sockfd, buf, MAX_MULTICAST_PKT_LEN, 0, (const void *)&saddr, sizeof(saddr));
			ret = sendto(sockfd, buf, MAX_MULTICAST_PKT_LEN, 0, (const void *)&saddr, sizeof(saddr));
			ret = sendto(sockfd, buf, MAX_MULTICAST_PKT_LEN, 0, (const void *)&saddr, sizeof(saddr));
			ret = sendto(sockfd, buf, MAX_MULTICAST_PKT_LEN, 0, (const void *)&saddr, sizeof(saddr));
			ret = sendto(sockfd, buf, MAX_MULTICAST_PKT_LEN, 0, (const void *)&saddr, sizeof(saddr));

			printf("IP sent to client :%s\n", clientIP);
		}
	}

	close(sockfd);

end:
   return;
}

char *getSystemIP(char *IP, char *interfaceName)
{
    char ifList[MAX_BUF] = {0};
    int SD;
    int interfaces = 0;
    int index;
    struct  ifconf ifc = {0};
    struct  ifreq *pIfrReq = NULL;


    if((NULL == IP) || (NULL == interfaceName)) {
        printf("Invalid arguments\n");
        return NULL;
    }

    /** Get a socket handle */
    SD = socket(AF_INET, SOCK_DGRAM, 0);
    if(SD < 0) {
        printf("socket failed\n");
        return NULL;
    }
 
    /** Query available interfaces */
    ifc.ifc_len = sizeof(ifList);
    ifc.ifc_buf = ifList;

    if(ioctl(SD, SIOCGIFCONF, &ifc) < 0) {
        (void)close(SD);
        printf("ioctl(SIOCGIFCONF) failed\n");
        return NULL;
    }
 
    /** Iterate through the list of interfaces */
    pIfrReq = ifc.ifc_req;
    interfaces = ifc.ifc_len / sizeof(struct ifreq);

    for(index=0; index<interfaces; index++) {
        if ( !strcmp(pIfrReq->ifr_name, interfaceName) ) {
            (void)close(SD);
            return getIP(&pIfrReq->ifr_addr, IP);
        }
        pIfrReq++;
    }

    (void)close(SD);
    return NULL;
}

char *getIP(const struct sockaddr *SA, char *IP)
{
    if(NULL == IP)
        return NULL;

    switch(SA->sa_family) 
    {
        case AF_INET6:
        case AF_INET:
            if( NULL == inet_ntop(AF_INET, &(((struct sockaddr_in *)SA)->sin_addr), IP, MAX_IPV4_IP_LEN))
				return NULL;
            break;

         default:
            strncpy(IP, "Unknown IF", MAX_IPV4_IP_LEN);
            return NULL;
    }

    return IP;
}

